﻿using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace CountTools
{
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    public class CodeCount : IExternalCommand
    {
        private string path;

        public Result Execute(ExternalCommandData cmdData, ref string msg, ElementSet elements)
        {
            UIDocument uidoc = cmdData.Application.ActiveUIDocument;
            Document doc = uidoc.Document;

            this.path = doc.PathName;
            int lastChar = path.LastIndexOf(@"\");
            path = path.Remove(lastChar + 1);
            path += doc.Title.Substring(0, doc.Title.Length - 4) + "算量信息.xml";
            XmlDocument xml = new XmlDocument();
            xml.Load(path);

            List<string> elementTypes = new List<string>();
            Dictionary<string, List<string>> elementsList = new Dictionary<string, List<string>>();
            XmlNode mainNode = xml.SelectSingleNode("算量信息");
            var nodes = mainNode.ChildNodes;
            foreach (XmlNode childNode in nodes)
            {
                string elementId = childNode.Name;
                XmlNode name = childNode.SelectSingleNode("项目名称");
                string codeName = name.InnerText;

                if (elementsList.ContainsKey(codeName))
                {
                    elementsList[codeName].Add(elementId);
                }
                else
                {
                    elementsList.Add(codeName, new List<string>());
                    elementsList[codeName].Add(elementId);
                    elementTypes.Add(codeName);
                }
            }

            XmlDocument xmlRebar = new XmlDocument();
            string newPath = path.Replace("清单规则", "算量信息");
            //if (File.Exists(newPath))
            //{
            //    elementTypes.Add("010515001 现浇构件钢筋");
            //}

            elementTypes.Sort();

            CodeCountRuleForm ruleForm = new CodeCountRuleForm(elementTypes, path);
            ruleForm.ShowDialog();
            List<string> resultList = ruleForm.CodeList;


            if (ruleForm.DialogResult == System.Windows.Forms.DialogResult.OK)
            {
                int count = 0;
                int total = 0;
                for (int i = 0; i < elementsList.Keys.Count; i++)
                {
                    string codeName = elementsList.Keys.ElementAt(i);
                    total += elementsList[codeName].Count;
                }

                ProgressBarExport progressBar = new ProgressBarExport();
                progressBar.Text = "计算工程量";
                progressBar.progressBarEx.Minimum = 0;
                progressBar.SetTextInfo("计算工程量(" + count.ToString() + "/" + total.ToString() + ")", 0L);
                progressBar.Show();
                progressBar.progressBarEx.Maximum = total;

                for (int i = 0; i < elementsList.Keys.Count; i++)
                {
                    string codeName = elementsList.Keys.ElementAt(i);
                    string keyWords = "";
                    for (int j = 0; j < resultList.Count; j++)
                    {
                        if (resultList[j].Contains(codeName))
                        {
                            keyWords = resultList[j].Split('-')[1];
                            break;
                        }
                    }
                    for (int j = 0; j < elementsList[codeName].Count; j++)
                    {
                        ElementId id = new ElementId(int.Parse(elementsList[codeName][j].Remove(0, 2)));
                        Element element = doc.GetElement(id);
                        string numText = GetCountText(element, keyWords);
                        string unitText = GetUintText(keyWords);
                        XmlNode idNode = mainNode.SelectSingleNode(elementsList[codeName][j]).SelectSingleNode("工程量");
                        XmlNode textNode = mainNode.SelectSingleNode(elementsList[codeName][j]).SelectSingleNode("单位");
                        idNode.InnerText = numText;
                        textNode.InnerText = unitText;

                        count++;
                        progressBar.PerformStep();
                        progressBar.SetTextInfo("计算工程量(" + count.ToString() + "/" + total.ToString() + ")", 0L);
                        if (progressBar.progressBarEx.Value == total)
                        {
                            progressBar.Dispose();
                        }
                        if (progressBar.bAbort)
                        {
                            progressBar.Dispose();
                            progressBar.Close();
                            return Result.Cancelled;
                        }
                    }
                }
                xml.Save(path);
                TaskDialog.Show("Revit", "清单工程量计算完毕！！");
            }
            return Result.Succeeded;
        }

        private string GetUintText(string text)
        {
            switch (text)
            {
                case "体积":
                    return "m3";

                case "面积":
                    return "m2";

                case "长度":
                    return "m";

                case "数量":
                    return "个";

                default:
                    return "";
            }
        }

        private string GetCountText(Element element, string text)
        {
            switch (text)
            {
                case "体积":
                    return GetVolumn(element);
                case "面积":
                    return GetArea(element);
                case "长度":
                    return GetLength(element);
                case "数量":
                    return "1";
                default:
                    return "";
            }
        }

        private string GetLength(Element element)
        {
            Document doc = element.Document;
            switch (element.Category.Name)
            {
                case "墙":
                    double volumnWall = element.get_Parameter(BuiltInParameter.CURVE_ELEM_LENGTH).AsDouble();
                    return Math.Round(volumnWall * 0.3048, 3).ToString();

                case "结构框架":
                    double volumnBeam = element.get_Parameter(BuiltInParameter.INSTANCE_LENGTH_PARAM).AsDouble();
                    return Math.Round(volumnBeam * 0.3048, 3).ToString();

                default:
                    return "";
            }
        }

        private string GetArea(Element element)
        {
            Document doc = element.Document;
            switch (element.Category.Name)
            {
                case "楼板":
                case "墙":
                    double volumnWall = element.get_Parameter(BuiltInParameter.HOST_AREA_COMPUTED).AsDouble();
                    return Math.Round(volumnWall * 0.3048 * 0.3048, 3).ToString();
                default:
                    return "";
            }
        }

        private string GetVolumn(Element element)
        {
            Document doc = element.Document;
            switch (element.Category.Name)
            {
                case "楼板":
                case "墙":
                case "结构框架":
                case "结构柱":
                    double volumnWall = element.get_Parameter(BuiltInParameter.HOST_VOLUME_COMPUTED).AsDouble();
                    return Math.Round(volumnWall * 0.3048 * 0.3048 * 0.3048, 3).ToString();
                default:
                    return "";
            }
        }
    }
}
